package network

import (
	"bytes"
	_ "bytes"
	_ "encoding"
	"encoding/binary"
	_ "encoding/binary"
	"errors"
	_ "fmt"
	"github.com/davecgh/go-spew/spew"
	_ "github.com/golang/protobuf/proto"
	"github.com/hprose/hprose-golang/io"
	"go-tcpFramework-rudy/logger"
	"go-tcpFramework-rudy/util"
	"golang.org/x/net/context"
	"log"
	"net"
	"os"
	"strconv"
	"sync"
	"time"
	_ "time"
)

const (
	PKG_MAX_LENGTH = 1024
)

var (
	ERR_CHAN_CLOSE = errors.New("CHANEL CLOSED")
)

type PackHeader struct {
	Identify [2]byte
	Length   int32
	Verify   byte
}

type PackageHandler interface {
	Read() []byte
	Write([]byte)
}

type ProcessContext struct {
	context   context.Context
	receiever *PackageReceiever
	c         *net.Conn
	h         HandleFunction
}

//todo 如果需要接收方多携程，还需要实现一个mutex
type PackageReceiever struct {
	pack_data     []byte //正在组包的数据
	pack_len      int
	cache_package chan []byte
	reader        io.Reader
	mutex         sync.Mutex
	PackageHandler
}

func (this *PackageReceiever) Cleared() bool {
	// 没有正在缓存的数据包
	if len(this.cache_package) == 0 && this.pack_len == 0 {
		return true
	} else {
		return false
	}
}
func (this *PackageReceiever) PackageCleared() bool {
	if len(this.cache_package) == 0 {
		return true
	} else {
		return false
	}
}
func (this *PackageReceiever) Unsort() bool {
	if this.pack_len == 0 {
		return false
	} else {
		return true
	}
}

func (this *PackageReceiever) ReadNonBlock() ([]byte, error) {
	if len(this.cache_package) > 0 {
		ret, ok := <-this.cache_package
		if ok != true {
			return nil, ERR_CHAN_CLOSE
		}
		return ret[7:], nil
	} else {
		return nil, nil
	}
}

/*
type FrameHeader struct {
	Segment [4]byte
	Length int64
	Verify byte
}
*/
var (
	ErrPackFormat    = errors.New("Error Package format error")
	ErrorPackTooLong = errors.New("Package too long")
	ErrorPackVerify  = errors.New("Package verify fail")
)

func PackageReceieverFactory() *PackageReceiever {
	obj := new(PackageReceiever)
	obj.pack_data = make([]byte, util.MAX_PACKAGE_BUFFER)
	//最大缓存的包数据
	obj.cache_package = make(chan []byte, PKG_MAX_LENGTH)
	return obj
}

type UserError struct {
	Err string
}

func (this *UserError) Error() string {
	return this.Err
}

func (this *PackageReceiever) Write(input []byte, inputlen int) error {

	var unsort []byte
	var unsort_len int
	pack_start := 0
	if inputlen == 0 {
		return nil
	}
	//log.Println("recv data len:",inputlen)
	if this.pack_len > 0 {
		//log.Println("unstorage data",this.pack_len)
		copy(this.pack_data[this.pack_len:], input[0:inputlen])
		//log.Println(this.pack_data)
		this.pack_len += inputlen
		unsort = this.pack_data
		unsort_len = this.pack_len
	} else {
		unsort = input
		unsort_len = inputlen
	}
	//只有当负载数据包大于包头的时候才进行解包
	if unsort_len > 6 && unsort_len < util.MAX_PACKAGE_BUFFER {
		//获取各个包头地址
		for i := (0); i < unsort_len; {
			//包头的时候刚好出现粘包的情况
			if unsort_len - i < 7{
				//直接拷贝到未解包缓冲区
				copy(this.pack_data[0:], unsort[pack_start:unsort_len])
				this.pack_len = unsort_len - pack_start
				break
			}

			if unsort[0+i] != 0x40 || unsort[1+i] != 0x41 {
				//log.Println("unsort",unsort[0:inputlen],i)
				return ErrPackFormat
			}
			pack_start = i
			bpacklen := bytes.NewReader(unsort[i+2 : i+6])
			var packlen int32
			var verify byte
			e := binary.Read(bpacklen, binary.BigEndian, &packlen)
			if nil != e {
				logger.LogDebugError(e.Error())
			}
			for _, v := range unsort[i+2 : i+6] {
				verify += v
			}
			if verify != unsort[6] {
				return ErrorPackVerify
			}
			//下个包头的地址
			//log.Println("packlen:",packlen)
			i += int(packlen) + 7
			//如果i小于packlen证明出现了沾包的情况
			if i <= unsort_len {
				this.cache_package <- unsort[pack_start:i]
				pack_start = i
				this.pack_len = 0
			} else {
				//超过了当前缓冲区的话拷贝到缓存以便下次组包
				copy(this.pack_data[0:], unsort[pack_start:unsort_len])
				this.pack_len = unsort_len - pack_start
			}
		}
	} else {
		if unsort_len == 0 {
			return nil
		} else {
			return ErrorPackTooLong
		}
	}
	return nil
}

type HandleFunction func(ctx ProcessContext)

var gHandler HandleFunction = nil

func SetHandler(h HandleFunction) {
	gHandler = h
}

func DefaultPackageHandler(ctx ProcessContext) {
	pack, e := ctx.receiever.ReadNonBlock()
	if e != nil {
		logger.LogDebugError(e.Error())
		return
	}
	logger.LogRealeaseInfo((*ctx.c).RemoteAddr().String() + "[send]" + spew.Sprintf("%v", pack))
	_, e = (*ctx.c).Write(pack)
	if e != nil {
		logger.LogDebugError(e.Error())
	}
}

func HandleConnection(c ConnectionContext) {
	flagStop := false
	flagRestart := false
	buf := make([]byte, PKG_MAX_LENGTH) // 这个1024可以根据你的消息长度来设置
	packReceiever := PackageReceieverFactory()
	pCtx := ProcessContext{c, packReceiever, &c.Cnn,c.h}
	/*
		e := c.Cnn.SetDeadline(time.Now().Add(time.Second))
		if nil != e{
			log.Print(e.Error())
		}*/
	for {
		env := os.Getenv(util.ENV_GRACEFUL_RESTART)
		if env == "true" {
			flagRestart = true
		}
		if flagStop || flagRestart {
			if packReceiever.Unsort() {
				// 没有未接受完成的包和还没被处理的数据包
				//todo 向 fd缓存列表添加fd然后退出线程，但是不关闭socket
				//还有包没收完全，一般这种情形只有在热更新重启时候会出现，客户端的数据包一般不会主动断开

				//把最后一个包收完，然后执行最后一个包的callback，退出该线程,然后置位waitgroup
				reservePack := make([]byte, packReceiever.pack_len)
				_, err := c.Cnn.Read(reservePack)
				logger.LogRealeaseInfo(reservePack)
				if nil != err {
					logger.LogDebugError(err.Error())
				}
				e := packReceiever.Write(reservePack, len(reservePack))
				if nil != e {
					logger.LogDebugError(e.Error())
					return
				}

			}
			for !packReceiever.Cleared() {
				c.h(pCtx)
			}
			break
		}
		for !packReceiever.PackageCleared() {
			//修改handler 机制
			if nil != gHandler {
				gHandler(pCtx)
			} else {
				c.h(pCtx)
			}
		}

		//重启
		var n int
		var err error
		if flagRestart {
			// 重启情况下
			n, err = c.Cnn.Read(buf)
		} else {
			// n为一次Read实际得到的消息长度
			n, err = c.Cnn.Read(buf)
		}
		//var req protocol.Request
		if err != nil {
			if nerr, ok := err.(net.Error); ok && !nerr.Temporary() {
				if !flagStop {
					flagStop = true
					e := c.Cnn.Close()
					if nil != e {
						logger.LogDebugError(e.Error())
					}
					close(packReceiever.cache_package)
					logger.LogRealeaseInfo("delete fd " + strconv.Itoa(int(c.fd)))
					e = GetConnMgr().DeleteConn(c.fd)
					if nil != e {
						logger.LogDebugError(e.Error())
					}
				} else {

				}
			}
		}
		logger.LogRealeaseInfo(buf)

		err = packReceiever.Write(buf, n)
		//注意，用了chanel不要在同一个携程里面进行插入和取出，以免造成死锁。
		if err != nil {
			log.Println(err.Error())
			//log.Println("conection drop down")
			e := c.Cnn.Close()
			if nil != e {
				logger.LogDebugError(e.Error())
			}
			t := <-packReceiever.cache_package
			if len(t) != 0 {
				close(packReceiever.cache_package)
			}
			e = GetConnMgr().DeleteConn(c.fd)
			if nil != e {
				logger.LogDebugError(e.Error())
			}
			return
		}
		if len(c.Done()) > 0 {
			l := <-c.Done()
			if dead, ok := c.Deadline(); ok {
				if time.Now().Add(time.Nanosecond).After(dead) {
					logger.LogRealeaseInfo("connection timeout")
					// timeout
				}
			} else {
				logger.LogRealeaseInfo("connection cancled")
				//canceld
			}
			l = l
		}

	}
}
